/*
 * 
 *  This file is part of Sourceprojects.org Lycia Copyright 2010 noctarius
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * 
 */
package org.sourceprojects.xmlparser;

import java.lang.reflect.Constructor;

import org.sourceprojects.lycia.LyciaParser;
import org.sourceprojects.lycia.LyciaParserFactory;
import org.sourceprojects.xmlparser.exceptions.XmlParserInitializationException;

/**
 * Defines a factory API that enables applications to obtain instances of the
 * {@link org.sourceprojects.xmlparser.XmlParser} either by given standard
 * implementations or by configuring own implementations.
 * 
 * @author noctarius
 * @since 0.0.1
 * @deprecated Use {@link LyciaParserFactory} instead
 */
@Deprecated
public final class XmlParserFactory {
	/**
	 * Classname for the standard {@link org.sourceprojects.xmlparser.XmlParser}
	 * class to be created if no special implementation is given
	 */
	public static final String STANDARD_XMLPARSER_CLASS = "org.sourceprojects.xmlparser.internal.XmlParserAdapter";

	/**
	 * Classname for the standard XmlParser
	 * {@link org.sourceprojects.xmlparser.ParserContext} class to be created if
	 * no special implementation is given
	 */
	private static String STANDARD_PARSERCONTEXT_CLASS = "org.sourceprojects.xmlparser.internal.ParserContextImpl";

	/**
	 * Obtain a new instance of a {@link org.sourceprojects.xmlparser.XmlParser}
	 * .<br>
	 * Implementations that used for
	 * {@link org.sourceprojects.xmlparser.XmlParser} and
	 * {@link org.sourceprojects.xmlparser.ParserContext} are the standard
	 * internal ones. The classloader to load up those implementations is the
	 * actual ContextClassLoader of the actual thread.
	 * 
	 * @param <B>
	 *            Type of output class to use in parsing and transforming
	 * @return New instance of standard XmlParser implementation
	 * @throws XmlParserInitializationException
	 *             If some exception occurs on initialization of the new
	 *             instance the exception is wrapped into a
	 *             {@link XmlParserInitializationException}
	 */
	public static final <B> XmlParser<B> newInstance()
			throws XmlParserInitializationException {

		final ClassLoader classLoader = Thread.currentThread()
				.getContextClassLoader();
		return newInstance(STANDARD_XMLPARSER_CLASS,
				STANDARD_PARSERCONTEXT_CLASS, classLoader);
	}

	/**
	 * Obtain a new instance of a {@link org.sourceprojects.xmlparser.XmlParser}
	 * .<br>
	 * Implementations that used for
	 * {@link org.sourceprojects.xmlparser.XmlParser} and
	 * {@link org.sourceprojects.xmlparser.ParserContext} are the standard
	 * internal ones. The classloader to load up those implementations is the
	 * given classloader.
	 * 
	 * @param <B>
	 *            Type of output class to use in parsing and transforming
	 * @param classLoader
	 *            The classloader to load classes
	 * @return New instance of standard XmlParser implementation
	 * @throws XmlParserInitializationException
	 *             If some exception occurs on initialization of the new
	 *             instance the exception is wrapped into a
	 *             {@link XmlParserInitializationException}
	 */
	public static final <B> XmlParser<B> newInstance(
			final ClassLoader classLoader)
			throws XmlParserInitializationException {

		return newInstance(STANDARD_XMLPARSER_CLASS,
				STANDARD_PARSERCONTEXT_CLASS, classLoader);
	}

	/**
	 * Obtain a new instance of a {@link org.sourceprojects.xmlparser.XmlParser}
	 * .<br>
	 * Implementations that used for
	 * {@link org.sourceprojects.xmlparser.XmlParser} and
	 * {@link org.sourceprojects.xmlparser.ParserContext} must be given as
	 * parameters to the method. The classloader to load up those
	 * implementations is the given classloader.<br>
	 * {@link XmlParserInitializationException} will be thrown if one of both
	 * implementations is null or not found.
	 * 
	 * @param <B>
	 *            Type of output class to use in parsing and transforming
	 * @param parserImplementationClassname
	 *            Classname of the implementation used for XmlParser
	 * @param contextImplementationClassname
	 *            Classname of the implementation used for ParserContext
	 * @param classLoader
	 *            The classloader to load classes
	 * @return New instance of standard XmlParser implementation
	 * @throws XmlParserInitializationException
	 *             If some exception occurs on initialization of the new
	 *             instance the exception is wrapped into a
	 *             {@link XmlParserInitializationException}
	 */
	public static final <B> XmlParser<B> newInstance(
			final String parserImplementationClassname,
			final String contextImplementationClassname,
			final ClassLoader classLoader)
			throws XmlParserInitializationException {

		return newInstance(parserImplementationClassname,
				contextImplementationClassname, classLoader, true);
	}

	/**
	 * Obtain a new instance of a {@link org.sourceprojects.xmlparser.XmlParser}
	 * .<br>
	 * Implementations that used for
	 * {@link org.sourceprojects.xmlparser.XmlParser} and
	 * {@link org.sourceprojects.xmlparser.ParserContext} must be given as
	 * parameters to the method. The classloader to load up those
	 * implementations is the given classloader.<br>
	 * {@link XmlParserInitializationException} will be thrown if one of both
	 * implementations is null or not found.
	 * 
	 * @param <B>
	 *            Type of output class to use in parsing and transforming
	 * @param parserImplementationClassname
	 *            Classname of the implementation used for XmlParser
	 * @param contextImplementationClassname
	 *            Classname of the implementation used for ParserContext
	 * @param classLoader
	 *            The classloader to load classes
	 * @param createResourceResolver
	 *            Automatically create a basic ResourceResolver for the
	 * @return New instance of standard XmlParser implementation XmlParser
	 *         instance
	 * @throws XmlParserInitializationException
	 *             If some exception occurs on initialization of the new
	 *             instance the exception is wrapped into a
	 *             {@link XmlParserInitializationException}
	 * @since 0.0.6
	 */
	@SuppressWarnings("unchecked")
	public static final <B> XmlParser<B> newInstance(
			final String parserImplementationClassname,
			final String contextImplementationClassname,
			final ClassLoader classLoader, final boolean createResourceResolver)
			throws XmlParserInitializationException {

		try {
			Class<? extends XmlParser<B>> parserClass;
			Class<? extends ParserContext<B>> contextClass;
			parserClass = (Class<? extends XmlParser<B>>) classLoader
					.loadClass(parserImplementationClassname);

			contextClass = (Class<? extends ParserContext<B>>) classLoader
					.loadClass(contextImplementationClassname);

			final Constructor<? extends XmlParser<B>> constructor = parserClass
					.getConstructor(LyciaParser.class);

			final LyciaParser<B> lyciaParser = LyciaParserFactory
					.newInstance(classLoader);
			final XmlParser<B> parser = constructor.newInstance(lyciaParser);
			final ParserContext<B> context = contextClass.newInstance();
			parser.setParserContext(context);

			if (createResourceResolver) {
				parser.setResourceResolver(ResourceResolverFactory
						.newInstance(classLoader));
			}

			return parser;
		} catch (final Exception e) {
			e.printStackTrace();
			throw new XmlParserInitializationException(
					"Parser initialization failed", e);
		}
	}
}
